/*
 * Copyright (c) 2013-2018 上海汇数数据. All rights reserved.
 * @(#) Gender.java 2018-08-05 22:56
 */

package cn.jh.common.core.domain;

import cn.jh.common.core.i18n.I18n;
import com.fasterxml.jackson.annotation.JsonValue;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.util.Locale;


/**
 * 性别枚举。
 *
 * @author Fuchun
 * @since 1.0
 */
public enum Gender implements EnumValue<String>, TextValue<String, String> {

    /** 男（1）：{@code gender.male} */
    MALE(1, "Male", "gender.male", "M", "\u2642"),

    /** 女（2）：{@code gender.female} */
    FEMALE(2, "Female", "gender.female", "F", "\u2640"),

    /** 男孩（1）：{@code gender.boy} */
    BOY(1, "Boy", "gender.boy", "B", "\u2642"),

    /** 女孩（2）：{@code gender.girl} */
    GIRL(2, "Girl", "gender.girl", "G", "\u2640"),

    /** 未知（3）：{@code gender.unknown} */
    UNKNOWN(3, "Unknown", "gender.unknown", "N", "?")
    ;

    private final short code;
    private final String name;
    private final String i18nCode;
    private final String alias;
    private final String symbol;

    Gender(int code, String name, String i18nCode, String alias, String symbol) {
        this.code = (short) code;
        this.name = name;
        this.i18nCode = i18nCode;
        this.alias = alias;
        this.symbol = symbol;
    }

    @Contract(pure = true)
    @JsonValue
    public Short getCode() {
        return code;
    }

    @Contract(pure = true)
    public String getName() {
        return name;
    }

    @Contract(pure = true)
    public String getI18nCode() {
        return i18nCode;
    }

    @Contract(pure = true)
    public String getAlias() {
        return alias;
    }

    @Contract(pure = true)
    public String getSymbol() {
        return symbol;
    }

    @Override
    public String getText() {
        return getText(Locale.getDefault());
    }

    public String getText(Locale locale) {
        return I18n.getOrDefault(i18nCode, null, locale, name);
    }

    @Override
    public String getValue() {
        return alias;
    }

    /**
     * 返回指定标识的 {@code Gender} 枚举对象，如果标识为 {@code null}，
     * 或者不存在，则返回 {@link #UNKNOWN}。
     * <pre>
     * 如果指定{@code social == true}，1 =&gt; BOY; 2 =&gt; GIRL; other UNKNOWN
     * 否则 1 =&gt; MALE; 2 =&gt; FEMALE; other UNKNOWN
     * </pre>
     *
     * @param <N> 标识的类型。
     * @param code 标识。
     * @param social 是否用于社交。
     * @return 返回指定标识的 `Gender` 枚举对象。
     */
    @NotNull
    public static <N extends Number> Gender of(N code, boolean social) {
        short v;
        if (code == null || (v = code.shortValue()) <= 0) {
            return UNKNOWN;
        }
        switch (v) {
            case 1: return social ? BOY : MALE;
            case 2: return social ? GIRL : FEMALE;
            default:
                return UNKNOWN;
        }
    }

    /**
     * 返回指定标识的 {@code Gender} 枚举对象，如果标识为 {@code null}，
     * 或者不存在，则返回 {@link #UNKNOWN}。只返回{@code MALE, FEMALE, UNKNOWN}
     *
     * @param <N> 标识的类型。
     * @param code 标识。
     * @return 返回指定标识的 `Gender` 枚举对象。
     */
    @NotNull
    public static <N extends Number> Gender of(N code) {
        return of(code, false);
    }

    /**
     * 返回指定标识的 {@code Gender} 枚举对象，如果标识为 {@code null}，
     * 或者不存在，则返回 {@link #UNKNOWN}。只返回{@code BOY, GIRL, UNKNOWN}
     *
     * @param <N> 标识的类型。
     * @param code 标识。
     * @return 返回指定标识的 `Gender` 枚举对象。
     */
    @NotNull
    public static <N extends Number> Gender forSocial(N code) {
        return of(code, true);
    }

    /**
     * 返回指定字符串标识（名称、别名，或者编码）的枚举对象。
     *
     * @param input 字符串标识（名称、别名，或者编码）。
     * @return 返回指定字符串标识（名称、别名，或者编码）的枚举对象。
     */
    @NotNull
    public static Gender forString(String input) {
        String str;
        if (input == null || (str = input.trim()).isEmpty()) {
            return UNKNOWN;
        }
        for (Gender gender : values()) {
            if (str.equals(gender.name) || str.equals(gender.alias) ||
                    str.equals(gender.i18nCode)) {
                return gender;
            }
        }
        return UNKNOWN;
    }
}
